import json
from dataclasses import dataclass
from typing import Dict, Optional, List
import re
from enum import Enum
import json
import os
import time


@dataclass
class DeviceInfo:
    """设备信息数据类，包含设备的基本信息"""
    name: str  # 设备名称
    ip: str
    port: int
    username: str
    password: str
    enable_password: str


def get_device_info(device_id: str) -> Optional[DeviceInfo]:
    """
    从device.json文件中读取特定设备的信息
    
    Args:
        device_id: 设备ID，如'device1'、'device2'等
        
    Returns:
        DeviceInfo: 包含设备信息的数据类对象，如果设备不存在则返回None
    """
    try:
        # 读取device.json文件
        with open('./config/device.json', 'r', encoding='utf-8') as f:
            devices: Dict[str, Dict[str, any]] = json.load(f)
        
        # 检查设备ID是否存在
        if device_id not in devices:
            print(f"设备 {device_id} 不存在")
            return None
        
        # 获取设备信息
        device_data = devices[device_id]
        
        # 验证必需字段是否存在
        required_fields = ['ip', 'port', 'username', 'password']
        for field in required_fields:
            if field not in device_data:
                print(f"设备 '{device_id}' 缺少必需字段: {field}")
        
        # 创建并返回DeviceInfo对象
        return DeviceInfo(
            name=device_id,
            ip=device_data['ip'],
            port=device_data['port'],
            username=device_data['username'],
            password=device_data['password'],
            enable_password=device_data.get('enable_password', '')  # 使用get方法提供默认值
        )
        
    except FileNotFoundError:
        print("device.json文件不存在")
        return None
    except json.JSONDecodeError:
        print("device.json文件格式不正确")
        return None
    except KeyError as e:
        print(f"设备信息不完整，缺少字段: {e}")
        return None
    except Exception as e:
        print(f"读取设备信息时发生错误: {e}")
        return None

class ShellMode(Enum):
    """
    命令模式枚举类
    """
    INVAILD = -1
    NO_LOGIN = 0
    NORMAL = 1  # 普通模式
    ENABLE = 2  # 特权模式
    CONFIG = 3  # 配置模式
    LINUX  = 4  # linux shell
    OTHER  = 5  # 其他模式

# 全局缓存字典，用于存储不同配置文件的命令模式
_command_patterns_cache = {}
# 全局字典，用于存储不同配置文件的最后修改时间
_last_modified_times = {}

def load_command_patterns(config_file: str = './config/enable_patterns.json') -> List[str]:
    """
    从配置文件加载命令模式正则表达式，并使用缓存机制
    
    Args:
        config_file: 配置文件路径
        
    Returns:
        List[str]: 命令模式正则表达式列表
    """
    # 检查缓存是否存在且文件未修改
    try:
        # 检查文件是否存在
        if os.path.exists(config_file):
            # 获取文件的当前修改时间
            current_mtime = os.path.getmtime(config_file)
            
            # 检查缓存是否有效（缓存存在且文件未修改）
            if (config_file in _command_patterns_cache and 
                config_file in _last_modified_times and 
                _last_modified_times[config_file] == current_mtime):
                # 使用缓存值
                return _command_patterns_cache[config_file]
        else:
            print(f"文件不存在: {config_file}")
    except Exception as e:
        # 获取文件修改时间失败时，忽略异常，继续加载文件
        print(f"获取文件修改时间时发生错误: {e}")
    
    # 缓存无效或文件已修改，重新加载文件
    try:
        with open(config_file, 'r', encoding='utf-8') as f:
            config = json.load(f)
        patterns = config.get('enable_patterns', [])
        
        # 更新缓存和最后修改时间
        if os.path.exists(config_file):
            _last_modified_times[config_file] = os.path.getmtime(config_file)
        _command_patterns_cache[config_file] = patterns
        
        return patterns
    except FileNotFoundError:
        print(f"配置文件 {config_file} 不存在，使用默认命令模式")
        # 返回默认命令模式
        default_patterns = [
            r'^show\b',
            r'^clear\b',
            r'^debug\b',
            r'^more\b',
            r'^terminal\b',
            r'^ping\b',
            r'^write\b'
        ]
        # 更新缓存（即使文件不存在）
        _command_patterns_cache[config_file] = default_patterns
        return default_patterns
    except json.JSONDecodeError:
        print(f"配置文件 {config_file} 格式不正确，使用默认命令模式")
        # 返回默认命令模式
        default_patterns = [
            r'^show\b',
            r'^clear\b',
            r'^debug\b',
            r'^more\b',
            r'^terminal\b',
            r'^ping\b',
            r'^write\b'
        ]
        # 更新缓存
        _command_patterns_cache[config_file] = default_patterns
        return default_patterns
    except Exception as e:
        print(f"读取配置文件时发生错误: {e}，使用默认命令模式")
        # 返回默认命令模式
        default_patterns = [
            r'^show\b',
            r'^clear\b',
            r'^debug\b',
            r'^more\b',
            r'^terminal\b',
            r'^ping\b',
            r'^write\b'
        ]
        # 更新缓存
        _command_patterns_cache[config_file] = default_patterns
        return default_patterns


def get_command_mode(command: str) -> ShellMode:
    """
    根据命令判断命令模式
    
    Args:
        command: 要判断的命令字符串
        
    Returns:
        ShellMode: 命令模式枚举值
    """
    # 从缓存或配置文件加载命令模式（文件未修改时使用缓存，修改时重新加载）
    command_patterns = load_command_patterns()
    
    # 将命令转换为小写以进行不区分大小写的匹配
    command_lower = command.lower().strip()
    
    # 遍历正则模式列表进行匹配
    for pattern in command_patterns:
        if re.match(pattern, command_lower):
            return ShellMode.ENABLE
    
    # 未匹配到任何模式
    return ShellMode.CONFIG


# 示例使用
if __name__ == "__main__":
    # 读取device1的信息
    device1 = get_device_info('qer29-4')
    if device1:
        print(f"设备信息: 名称={device1.name}, IP={device1.ip}, 端口={device1.port}, 用户名={device1.username}, 启用密码={device1.enable_password}")
    
    # 读取device2的信息
    device2 = get_device_info('qer29-3')
    if device2:
        print(f"设备信息: 名称={device2.name}, IP={device2.ip}, 端口={device2.port}, 用户名={device2.username}, 启用密码={device2.enable_password}")
    
    # 尝试读取不存在的设备
    non_existent_device = get_device_info('device3')
    
    # 测试命令模式识别功能
    print("\n测试命令模式识别功能:")
    test_commands = [
        "show version",
        "clear interface",
        "debug ip packet",
        "configure terminal",
        "interface gigabitethernet1",
        "ping 127.0.0.1",
        "write memory"
    ]
    
    for cmd in test_commands:
        mode = get_command_mode(cmd)
        print(f"命令 '{cmd}' 的模式: {mode.name}")
    
    # 显示当前加载的命令模式配置
    print("\n当前加载的命令模式配置:")
    patterns = load_command_patterns()
    for pattern in patterns:
        print(f"- {pattern}")